#include "video.h"
#include "tables.h"
#include "timer.h"
#include "paging.h"
#include "multiboot.h"
#include "initrd.h"
#include "fs.h"
#include "print.h"
#include "kb.h"
#include "task.h"
#include "syscall.h"

extern unsigned int placement_address;
extern fs_node_t *fs_root;
unsigned int initial_esp;

void init(struct multiboot *mboot)
{
	gdtInstall();	// global descriptor table
	idtInstall();	// interrupt descriptor table
	initVideo();	// initialize video driver
	cls();		// clear the screen
	keyboardInstall();	// install the keyboard driver
	
	// disable interrupts until we're ready
	disable();
	
	timerInstall(50);	// install timer at 50hz
	
	// Find the location of our initial ramdisk.
	//ASSERT(mboot_ptr->mods_count > 0);
	unsigned int initrd_location = *((unsigned int*)mboot->mods_addr);
	unsigned int initrd_end = *(unsigned int*)(mboot->mods_addr+4);
	// Don't trample our module with placement accesses
	placement_address = initrd_end;
	
	// initialize paging
	initialize_paging();

	// Initialise the initial ramdisk, and set it as the filesystem root.
	fs_root = initialize_initrd(initrd_location);
	
	// initialize multi-tasking
	initialize_tasking();
	// initialize system calls
	initialize_syscalls();
	enable();
	// aaaaand go to user-mode
	user_mode();
}

void proc()
{
	char c;
	while(1)
	{
		c = syscall_getch();
		if(c != 0)
			syscall_print_ch(c);
	}
}

int main(struct multiboot *mboot_ptr, unsigned int initial_stack)
{
	// get our initial stack
	initial_esp = initial_stack;
	
	// initialize the kernel; after we return, we will be in the kernel process
	init(mboot_ptr);

	// here we should call something like 'init' for *nix
	// then just idle() after that, for a default process
	// shouldn't exit after that, so a panic should be after that
	
	// we're in the kernel process
	syscall_printf("Process #");
	syscall_print_dec(getpid());
	syscall_print_ch('\n');
	
	new_task(&proc);
	
	panic("Kernel quitting...");
	
	return 0;
}
